package net.alche.fa.core.parse;

import net.alche.fa.core.FaPlatform;
import java.util.Map;
import java.util.HashMap;
import net.alche.fa.core.model.FaValue;
import net.alche.al.util.AC;

//
// FaKeyWord
//
public class FaKeyWord {
  FaPlatform plat;
  private static Map<String,Boolean> operation = new HashMap<> ();
  private static String[] javWord;
  private static String[] MathWord = {"+", "-", "*", "/", "%" };
  private static String[] CompareWord = {"==", "!=", ">", ">=", "<", "<=" };
  private static String[] IfWord = {"if", "else-if", "else", "&&", "||", "?", "switch", "case", "default", "continue", "break" };
  private static String[] GiveWord = {"=", "+=", "-=", "*=", "/=", "%=" };
  private static String[] LoopWord = {"for", "while" };
  private static String[] SpecialWord = {"new", "var", "return", "@", "package", "class", "extends", "like", "try", "catch", "join", "between", "on", "in", "<>", "fa:", "catch", "static", "final" };
  private static String[] SymbolWord = {"(", ")", "[", "]", "{", "}", "!", ",", ".", ":", ";", "=>", "()" };
  private static String[] MathSingle = {"++", "--" };
  private static String[] dataType = {"String", "int", "boolean", "void","long", "double", "char", "[]", "Date", "Map", "List", "Object", "Exception", "Long", "Byte", "Character", "Double", "Integer", "Boolean"};
  private static String[] baseValue = {"true", "false", "null", "0", "1", "{}" };
  private static String[] priority0 = {"fa:", "()", "(", ")" };
  private static String[] priority01 = {"." };
  private static String[] priority1 = {"[" };
  private static String[] priority2 = {"++", "--", "!", "var" };
  private static String[] priority3 = {"*", "/", "%" };
  private static String[] priority4 = {"+", "-" };
  private static String[] priority6 = {"<", "<=", ">", ">=", "==", "!=" };
  private static String[] priority7 = {""};
  private static String[] priority11 = {"&&" };
  private static String[] priority12 = {"||" };
  private static String[] priority125 = {":" };
  private static String[] priority13 = {"{", ":", "?", "new" };
  private static String[] priority14 = {"=", "+=", "-=", "*=", "/=", "%=" };
  private static String[] priority15 = {"try", "return", "break", "continue", "catch" };
  public static String[] rightLowSytax = {",", ";", "(", "[" };
  public static Map<String,Boolean> pojoNameMap = new HashMap<> ();

  public static String[] getJavWord() {
    if ( javWord == null) {
      initJav();
    }
    return javWord;
  }

  public static void initJav() {
    if ( javWord != null) {
      return;
    }
    int length = MathWord.length + CompareWord.length + LoopWord.length + IfWord.length + GiveWord.length + SpecialWord.length + SymbolWord.length + MathSingle.length;
    javWord = new String[length] ;
    int i = 0;
    i = fillWords(javWord, MathWord, i);
    i = fillWords(javWord, CompareWord, i);
    i = fillWords(javWord, LoopWord, i);
    i = fillWords(javWord, IfWord, i);
    i = fillWords(javWord, GiveWord, i);
    i = fillWords(javWord, SpecialWord, i);
    i = fillWords(javWord, SymbolWord, i);
    i = fillWords(javWord, MathSingle, i);
    fillMap(MathWord, operation);
    fillMap(CompareWord, operation);
    fillMap(IfWord, operation);
    fillMap(GiveWord, operation);
    fillMap(LoopWord, operation);
    fillMap(SpecialWord, operation);
    fillMap(SymbolWord, operation);
    fillMap(MathSingle, operation);
  }

  private static int fillWords(String[] javWord, String[] words, int i) {
    int k = 0;
    for ( ; k < words.length; i++) {
      javWord[i] = words[k++ ];
    }
    return i;
  }

  private static void fillMap(String[] words, Map<String,Boolean> map) {
    for ( String word: words) {
      map.put(word, true);
    }
  }

  public static boolean isKeyWord(String word) {
    return arrContain(getJavWord(), word);
  }

  public static boolean isBaseDataType(String word) {
    return arrContain(dataType, word);
  }

  public boolean isDataType(String word) {
    if ( isOperation(word)) {
      return false;
    }
    if ( isBaseValue(word)) {
      return false;
    }
    if ( arrContain(dataType, word)) {
      return true;
    }
    // if FaDo.isObject(word)
    //   return true
    if ( pojoNameMap.get(word) != null) {
      return true;
    }
    if ( word.contains("<")) {
      if ( "<".equals(word) || "<=".equals(word)) {
        return false;
      }
      return true;
    }
    else if ( this.plat.isSageName(word)) {
      return true;
    }
    else if ( word.endsWith("[]") && word.length() > 3) {
      return true;
    }
    return false;
  }

  public static FaValue getDataType(String word) {
    if ( word == null) {
      return null;
    }
    if ( AC.reg.test("^\".*\"$", word)) {
      return new FaValue(word.substring(1, word.length() - 1), FaValue._STRING);
    }
    if ( AC.reg.test("^\'.*\'$", word)) {
      return new FaValue(word.charAt(1), FaValue._CHAR);
    }
    else if ( AC.reg.test("(^[0-9][0-9]*)|(^\\-[0-9][0-9]*)", word)) {
      return new FaValue(Integer.parseInt(word), FaValue._INT);
    }
    else if ( AC.reg.test("(^[0-9][0-9\\.]*)|(^\\-[0-9][0-9\\.]*)", word)) {
      return new FaValue(Double.parseDouble(word), FaValue._DOUBLE);
    }
    else if ( "true".equals(word) || "false".equals(word)) {
      return new FaValue(Boolean.parseBoolean(word), FaValue._BOOL);
    }
    else if ( "null".equals(word)) {
      FaValue fv = new FaValue();
      fv.setNull(true);
      return fv;
    }
    else if ( isVar(word)) {}
    return null;
  }

  public static FaValue getBaseFaValue(String word) {
    if ( word == null) {
      return null;
    }
    if(word.startsWith("\"")&&word.endsWith("\"")){
      return new FaValue(word.substring(1, word.length() - 1), FaValue._STRING);
    }
    // if ( AC.reg.test("^\".*\"$", word)) {
    //   return new FaValue(word.substring(1, word.length() - 1), FaValue._STRING);
    // }
    if ( AC.reg.test("^\'.*\'$", word)) {
      if ( word.length() == 2) {
        return new FaValue('\0', FaValue._CHAR);
      }
      else {
        return new FaValue(word.charAt(1), FaValue._CHAR);
      }
    }
    else if ( AC.reg.test("(^[0-9][0-9]*)|(^\\-[0-9][0-9]*)", word)) {
      if ( word.length() >= 9) {
        return new FaValue(Long.parseLong(word), FaValue._LONG);
      }
      else {
        return new FaValue(Integer.parseInt(word), FaValue._INT);
      }
    }
    else if ( AC.reg.test("(^[0-9][0-9\\.]*)|(^\\-[0-9][0-9\\.]*)", word)) {
      return new FaValue(Double.parseDouble(word), FaValue._DOUBLE);
    }
    else if ( "true".equals(word) || "false".equals(word)) {
      return new FaValue(Boolean.parseBoolean(word), FaValue._BOOL);
    }
    else if ( "null".equals(word)) {
      FaValue fv = new FaValue();
      fv.setNull(true);
      return fv;
    }
    return null;
  }

  public static boolean isBaseValue(String word) {
    if ( arrContain(baseValue, word)) {
      return true;
    }
    return AC.reg.test("(^[0-9][0-9\\.]*)|(^\\-[0-9][0-9\\.]*)", word) || AC.reg.test("^\".*\"$", word);
  }

  public static boolean isNumber(String word) {
    return AC.reg.test("(^[0-9][0-9\\.]*)|(^\\-[0-9][0-9\\.]*)", word);
  }

  public static boolean isRowJav(String word) {
    return "if else-if else for while var return @ switch case continue break default class".contains(word) || word.startsWith("fa-");
  }

  public static boolean isSingleJav(String word) {
    if ( word == null) {
      return false;
    }
    return "else return default".contains(word);
  }

  public static boolean isVar(String str) {
    return AC.reg.test("^[a-zA-Z_]+[a-zA-Z0-9_\\.]*", str);
  }

  public static boolean isOperation(String word) {
    if ( operation.get(word) != null || word.startsWith("fa-") || word.startsWith("var-") || word.startsWith("s-")) {
      return true;
    }
    return false;
  }

  public static boolean isMath(String word) {
    return arrContain(MathWord, word);
  }

  public static boolean frontNotParams(String front) {
    if ( isMath(front)) {
      return true;
    }
    return false;
  }

  public static boolean isData(String word) {
    if ( isVar(word) || isBaseValue(word)) {
      return true;
    }
    return false;
  }

  public static boolean isGive(String word) {
    return arrContain(GiveWord, word);
  }

  public static int getOperPriority(String operWord) {
    if ( operWord.startsWith("var-")) {
      return 5;
    }
    if ( operWord.startsWith("fa-")) {
      return 90;
    }
    if ( arrContain(priority0, operWord)) {
      return 0;
    }
    if ( arrContain(priority01, operWord)) {
      return 5;
    }
    if ( arrContain(priority1, operWord)) {
      return 10;
    }
    if ( arrContain(priority2, operWord)) {
      return 15;
    }
    if ( arrContain(priority3, operWord)) {
      return 20;
    }
    if ( arrContain(priority4, operWord)) {
      return 25;
    }
    if ( arrContain(priority6, operWord)) {
      return 30;
    }
    if ( arrContain(priority7, operWord)) {
      return 35;
    }
    if ( arrContain(priority11, operWord)) {
      return 40;
    }
    if ( arrContain(priority12, operWord)) {
      return 45;
    }
    if ( arrContain(priority125, operWord)) {
      return 50;
    }
    if ( arrContain(priority13, operWord)) {
      return 55;
    }
    if ( arrContain(priority14, operWord)) {
      return 60;
    }
    if ( arrContain(priority15, operWord)) {
      return 65;
    }
    return 100;
  }

  public static boolean arrContain(String[] arr, String word) {
    for ( String key: arr) {
      if ( key.equals(word)) {
        return true;
      }
    }
    return false;
  }

  public static void setJavWord(String[] javWord) {
    FaKeyWord.javWord = javWord;
  }

  public FaPlatform getPlat(){
    return this.plat;
  }
  public void setPlat(FaPlatform plat){
    this.plat = plat;
  }}